/**
 * 
 */
package org.compiere.process;

import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.logging.Level;

import org.compiere.acct.Doc;
import org.compiere.acct.Doc_GLJournal;
import org.compiere.acct.Fact;
import org.compiere.apps.ADialog;
import org.compiere.model.MAccount;
import org.compiere.model.MAccountCombination;
import org.compiere.model.MAcctSchema;
import org.compiere.model.MBPartner;
import org.compiere.model.MFactAcct;
import org.compiere.model.MJournal;
import org.compiere.model.MJournalBatch;
import org.compiere.model.MJournalLine;
import org.compiere.model.MTable;
import org.compiere.model.Mhrmpayment;
import org.compiere.model.Mhrmpaymentlist;
import org.compiere.model.Query;
import org.compiere.model.X_A_Depreciation_Build;
import org.compiere.model.X_C_Period;
import org.compiere.model.X_GL_Category;
import org.compiere.util.DB;
import org.compiere.util.Env;

import extend.org.compiere.utils.Util;

/**
 * @author Y.Ibrayev
 *
 */
public class HRMPaymentReversal extends SvrProcess {

	protected static final Integer I_ZERO = new Integer(0);
	
	private int C_Period_ID = 0;
	private int p_AD_Client_ID;
	private int p_AD_Org_ID;
	private int c_currency_id = 0;
	private int c_doctype_id = 0;
	private int gl_category_id = 0;
	private int hrm_payment_ID = 0;
	private int C_BPartner_ID = 0;
	
	private MJournalBatch batch = null;
	private Mhrmpayment hrmpayment = null;
	
	private String resultIt = null;
	private ProcessInfo processInfo;
	private X_C_Period period = null;
	private MBPartner partner = null;
	
	/* (non-Javadoc)
	 * @see org.compiere.process.SvrProcess#prepare()
	 */
	@Override
	protected void prepare() {
		processInfo = getProcessInfo();
		ProcessInfoParameter[] para = getParameter();
        p_AD_Org_ID  = Env.getAD_Org_ID(getCtx());
        p_AD_Client_ID = Env.getAD_Client_ID(getCtx());
        
        gl_category_id = getGLCategory();
        c_currency_id = getC_Currency_ID();
        BigDecimal tmp;
        
		for (int i = 0; i < para.length; i++) {
			String name = para[i].getParameterName();
			if (para[i].getParameter() == null)
				;
			else if (name.equals("hrm_payment_ID")) {
				tmp = (BigDecimal)para[i].getParameter();
				hrm_payment_ID = tmp.intValue();
			} else if (name.equals("C_BPartner_ID")) { 
				tmp = (BigDecimal)para[i].getParameter();
				C_BPartner_ID = tmp.intValue();
			}
		}
		
		if (hrm_payment_ID > 0) {
			hrmpayment = new Mhrmpayment(getCtx(),hrm_payment_ID,get_TrxName());
			if (hrmpayment != null) {
				period = Util.getPeriod(hrmpayment.getDateFrom());
				C_Period_ID  = (period != null ? period.getC_Period_ID() : 0 );
			}
		}
		
		if (C_BPartner_ID > 0) {
			partner = new MBPartner(getCtx(),C_BPartner_ID,get_TrxName());
		}
		
		c_doctype_id = 1000000; //TODO Убрать статику
	}

	/**
	 * @return
	 */
	private int getGLCategory() {
		StringBuffer sql = new StringBuffer(); 
		String clientCheck = " AND AD_Client_ID=" + getAD_Client_ID();
        sql.append("SELECT GL_Category_ID FROM GL_Category "
		+ " WHERE isActive='Y' AND CategoryType = '"+X_GL_Category.CATEGORYTYPE_Manual+"'"
        +" AND isDefault = 'Y'"+clientCheck);
        gl_category_id = DB.getSQLValue(get_TrxName(), sql.toString());
		return gl_category_id;
	}

	/* (non-Javadoc)
	 * @see org.compiere.process.SvrProcess#doIt()
	 */
	@Override
	protected String doIt() throws Exception {
		if(hrmpayment != null) {
			if (hrmpayment.haveBPartner(C_BPartner_ID) ) {
				if (period != null) {
					if (!hrmpayment.haveCorrectDocument()) {
						if (!haveReversalGLJournal()) {
							resultIt = createReversalLJournal();
							
							if (resultIt.equals("OK")) {
								resultIt = postBatch();
							}
							
						} else {
							ADialog.info(25, null, "Для данного периода и сотрудника уже сущствует сторно документ");
						}
					} else {
						ADialog.info(25, null, "Для данного периода и сотрудника уже сущствует сторно документ");
						resultIt = "hrm payment have correct document. hrm_payment_ID = " + Integer.toString(hrmpayment.getReversal_ID());
					}
				} else {
					resultIt = "Period not found. C_Period_ID = " + Integer.toString(C_Period_ID);
				}
			} else {
				resultIt = "Business Partner not found. C_BPartner_ID = " + Integer.toString(C_BPartner_ID);
			}
		} else {
			resultIt = "hrm payment not found. hrm_payment_ID = " + Integer.toString(hrm_payment_ID);
		}
		return resultIt;
	}

	/**
	 * @return
	 */
	private String postBatch() {
		if (batch == null) {
			resultIt = "Error";
			return resultIt;
		}
		batch.setProcessed(true);
		batch.saveEx(get_TrxName());
		batch.processIt(MJournalBatch.DOCACTION_Complete);
		
		String error = "";
		for(MJournal journal: batch.getJournals(false)) {
			MAcctSchema[] ass = getAcctSchema(journal);
			journal.processIt(DocAction.ACTION_Post);
			error = Doc.postImmediate(ass, MJournal.Table_ID, journal.getGL_Journal_ID(), true, journal.get_TrxName());
			log.log(Level.SEVERE,error);
		}
		resultIt = "OK";
		return resultIt;
	}

	/**
	 * @return
	 */
	private MAcctSchema[] getAcctSchema(MJournal journal) {
		MAcctSchema as = MAcctSchema.get(Env.getCtx(), journal.getC_AcctSchema_ID(), journal.get_TrxName());
		MAcctSchema[] ass = new MAcctSchema[1];
		ass[0] = as;
		return ass;
	}

	/**
	 * 
	 */
	private String createReversalLJournal() {
		try {
			batch = createBatch();
			if (batch == null) {
				return "Batch not saved";
			}
			createJournalReserved();
			createJournalHrmPayment();
			resultIt = "OK";
		} catch(Exception e) {
			log.log(Level.SEVERE,e.getMessage());
			resultIt = "Error";
		}
		return resultIt;
	}

	/**
	 * 
	 */
	private void createJournalHrmPayment() {
		MJournal Journal = new MJournal(batch);
		
		String DocumentNo = "!!!HRP:"+getDocumentNo(hrm_payment_ID,C_BPartner_ID,C_Period_ID);;
		
		Journal.setDocumentNo(DocumentNo);
		Journal.setDescription("HR: " + hrmpayment.getName());
		Journal.setC_DocType_ID(1000000);
		Journal.setDateDoc(hrmpayment.getDateAcct());
		Journal.setDateAcct(hrmpayment.getDateFrom());
		Journal.setC_Period_ID(period.getC_Period_ID());//get current period!
		Journal.setC_Currency_ID(c_currency_id);
		Journal.setC_AcctSchema_ID(1000000);
		Journal.setGL_Category_ID(1000000);
		Journal.setC_ConversionType_ID(1000001);
		Journal.saveEx();

		for(Mhrmpaymentlist line: hrmpayment.getLines()) {
			if (line.getC_BPartner_ID() == C_BPartner_ID) {
				String sql1 = "SELECT * FROM Fact_Acct \n"
					    + "WHERE AD_Org_ID = ? \n"
					    + "  AND AD_Client_ID = ? \n"
					    + "  AND AD_Table_ID = ? \n"
					    + "  AND Record_ID = ? \n "
					    + "  AND PostingType = ? \n"
					    + "  AND C_BPartner_ID = ?";
				int temp_AD_Org_ID = hrmpayment.getAD_Org_ID();
				int temp_AD_Cleint_ID = hrmpayment.getAD_Client_ID();
				int temp_AD_Table_ID = MTable.getTable_ID(hrmpayment.get_TableName());
				int temp_Record_ID = hrmpayment.gethrm_payment_ID();
				String temp_PostingType = Fact.POST_Actual; 
				PreparedStatement pstmt1 = null;
				ResultSet rs1 = null;
				try {
					pstmt1 = DB.prepareStatement(sql1, hrmpayment.get_TrxName());
					pstmt1.setInt(1, temp_AD_Cleint_ID);
					pstmt1.setInt(2, temp_AD_Org_ID);
					pstmt1.setInt(3, temp_AD_Table_ID);
					pstmt1.setInt(4, temp_Record_ID);
					pstmt1.setString(5, temp_PostingType);
					pstmt1.setInt(6,C_BPartner_ID);
					rs1 = pstmt1.executeQuery();
					int lin = 0;
					while(rs1.next()) {
						lin += 10;
						MFactAcct fa = new MFactAcct(Env.getCtx(),rs1,get_TrxName());
						MJournalLine journalLine = new MJournalLine(Journal);
						MAccount acct = null;
						try {
							acct = MAccount.get(fa);
						} catch(Exception e) {
							log.log(Level.SEVERE,e.getMessage());
						}
						
						int C_ValidCombonation_ID = 0;
						if (acct == null) {
							MAccountCombination ac = getValidComnination(fa);
							if (ac != null) C_ValidCombonation_ID = ac.getC_ValidCombination_ID();
						} else {
							C_ValidCombonation_ID = acct.getC_ValidCombination_ID();
						}

						journalLine.setC_ValidCombination_ID(C_ValidCombonation_ID);
						journalLine.setLine(lin);
						journalLine.setC_Currency_ID(341);
						journalLine.setAmtAcctDr(fa.getAmtAcctDr().negate());
						journalLine.setAmtAcctCr(fa.getAmtAcctCr().negate());
						journalLine.setAmtSourceDr(fa.getAmtSourceDr().negate());
						journalLine.setAmtSourceCr(fa.getAmtSourceCr().negate());
						journalLine.setProcessed(true);
						journalLine.setA_CreateAsset(false);
						journalLine.setA_Processed(false);
						
						journalLine.saveEx(get_TrxName());
					}
				} catch(SQLException e) {
					log.log(Level.WARNING, e.getLocalizedMessage());
					resultIt = "Error";
				} finally {
					DB.close(rs1, pstmt1);
					rs1 =null;
					pstmt1 = null;
				}
			}
		}
	}


	/**
	 * @param fa
	 * @return
	 */
	private MAccountCombination getValidComnination(MFactAcct fa) {
		MAccountCombination result = null;
		
		String sql = " select c_validcombination_id from adempiere.c_validcombination where account_id = " + fa.getAccount_ID() + " and c_bpartner_id = " + C_BPartner_ID;
		
		PreparedStatement pstmt = null;
		ResultSet rs = null;

		try{
			pstmt = DB.prepareStatement(sql, null);
			rs = pstmt.executeQuery();
			if (rs.next()) {
				result = new MAccountCombination(getCtx(),rs.getInt(1),get_TrxName());
			}
		} catch(SQLException e){
			log.log(Level.WARNING, e.getLocalizedMessage());
		} finally	{
			DB.close(rs, pstmt);
			rs = null; pstmt = null;
		}
		return result;
	}

	/**
	 * 
	 */
	private void createJournalReserved() {
		MJournalBatch reversalBatch = getHrmPaymentBatch();
		
		for(MJournal reversalJournal: reversalBatch.getJournals(false) ){

			String DocumentNo = "!!!HRR:"+getDocumentNo(hrm_payment_ID,C_BPartner_ID,C_Period_ID);;
			
			MJournal Journal = new MJournal(batch);
			Journal.setDocumentNo(DocumentNo);
			Journal.setDescription("{->" + reversalJournal.getDocumentNo() + ") - " + partner.getName());
			Journal.setC_DocType_ID(1000000);
			Journal.setDateDoc(reversalJournal.getDateDoc());
			Journal.setDateAcct(reversalJournal.getDateAcct());
			Journal.setC_Period_ID(period.getC_Period_ID());//get current period!
			Journal.setC_Currency_ID(reversalJournal.getC_Currency_ID());
			Journal.setC_AcctSchema_ID(1000000);
			Journal.setGL_Category_ID(1000000);
			Journal.setC_ConversionType_ID(1000001);
			Journal.setReversal_ID(reversalJournal.getGL_Journal_ID());
			Journal.setC_ConversionType_ID(reversalJournal.getC_ConversionType_ID()); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
			Journal.saveEx(get_TrxName());
			for(MJournalLine reversalLine: reversalJournal.getLines(false)) {
				if (reversalLine.getC_ValidCombination().getC_BPartner_ID() == C_BPartner_ID) {
					MJournalLine JournalLine = new MJournalLine(Journal);
					JournalLine.setDescription("{->" + reversalLine.getDescription() + ")");
					JournalLine.setC_Currency_ID(reversalLine.getC_Currency_ID());
					JournalLine.sethrm_reserve_ID(reversalLine.gethrm_reserve_ID());
					JournalLine.sethrm_reservesectional_ID(reversalLine.gethrm_reservesectional_ID());
					JournalLine.setLine(reversalLine.getLine());
					JournalLine.setC_ValidCombination_ID(reversalLine.getC_ValidCombination_ID());
					JournalLine.setAmtSourceDr(reversalLine.getAmtSourceDr().negate());
					JournalLine.setAmtSourceCr(reversalLine.getAmtSourceCr().negate());
					JournalLine.setAmtAcctDr(reversalLine.getAmtAcctDr().negate());
					JournalLine.setAmtAcctCr(reversalLine.getAmtAcctCr().negate());
					JournalLine.setProcessed(true);
					JournalLine.setA_CreateAsset(false);
					JournalLine.setA_Processed(false);
					JournalLine.saveEx(get_TrxName());
				}
			}
		}
		
	}

	/**
	 * @return
	 */
	private MJournalBatch createBatch() {
		String DocumentNo = getDocumentNo(hrm_payment_ID,C_BPartner_ID,C_Period_ID);
		String Description = "!!! - " + hrmpayment.getName() +" (" + partner.getName() + ")";
		MJournalBatch result = new MJournalBatch(getCtx(),0,get_TrxName());
		result.setClientOrg(p_AD_Client_ID, p_AD_Org_ID);
		result.setDocumentNo(DocumentNo);
		result.setDescription(Description);
		result.setPostingType(X_A_Depreciation_Build.POSTINGTYPE_Actual);
		result.setGL_Category_ID(gl_category_id);
		result.setDateDoc(hrmpayment.getDateFrom());
		result.setDateAcct(hrmpayment.getDateAcct());
		result.setC_Period_ID(C_Period_ID);
		result.setC_Currency_ID(c_currency_id);
		result.setControlAmt(BigDecimal.valueOf(0));
		result.setC_DocType_ID(c_doctype_id);
		
		result.saveEx(get_TrxName());
		return result;
	}

	/**
	 * @return
	 */
	private boolean haveReversalGLJournal() {
		int batch_ID = getBatchID(C_Period_ID, C_BPartner_ID);
		return batch_ID > 0;
	}

	/**
	 * @param c_Period_ID2
	 * @param c_BPartner_ID2
	 * @return
	 */
	private int getBatchID(int c_Period_ID, int c_BPartner_ID) {
		int result = 0;
		if (hrm_payment_ID > 0 && c_Period_ID > 0 && c_BPartner_ID > 0) {
			String DocumentNo = getDocumentNo(hrm_payment_ID,c_BPartner_ID,c_Period_ID); 
			String whereClauseFinal = "IsActive = 'Y' AND DocumentNo = '"+DocumentNo+"' AND C_Period_ID = ?";
			List<MJournalBatch> list = new Query(getCtx(), MJournalBatch.Table_Name, whereClauseFinal, get_TrxName())
			.setParameters(c_Period_ID)
			.list();
			if (list.size() > 0)
				result = list.get(0).getGL_JournalBatch_ID();
		}
		return result;
	}

	private int getC_Currency_ID() {
		int result = 0;
		String sql ="SELECT C_Currency_ID FROM C_AcctSchema WHERE isActive='Y' and AD_Client_ID = ?";
        result = DB.getSQLValue(get_TrxName(), sql, p_AD_Client_ID);
		return result;
	}
	
	private MJournalBatch getHrmPaymentBatch() {
		MJournalBatch result = null;
		String batchNo ="HR Резерв: " + hrmpayment.getName();
		String whereClauseFinal = "DocumentNo = '"+batchNo+"' AND C_Period_ID = ?";
		List<MJournalBatch> list = new Query(getCtx(), MJournalBatch.Table_Name, whereClauseFinal, get_TrxName())
		.setParameters(C_Period_ID)
		.list();
		if (list.size() > 0)
			result = list.get(0);
		return result;
	}
	
	private String getDocumentNo(int hrm_payment_ID, int C_BPartner_ID, int C_Period_ID) {
		String result = Integer.toString(hrm_payment_ID) + Integer.toString(C_BPartner_ID) + Integer.toString(C_Period_ID);
		return result;
	}
}
